All files / src/app/recipes/[id]/components RecipeHero.tsx

0% Statements 0/5
0% Branches 0/10
0% Functions 0/2
0% Lines 0/5

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121                                                                                                                                                                                                                                                 
import {
  ActionIcon,
  Badge,
  Box,
  Group,
  Image,
  Text,
  Title,
} from '@mantine/core';
import {
  IconChefHat,
  IconClock,
  IconEdit,
  IconFlame,
  IconUsers,
} from '@tabler/icons-react';
import type { Route } from 'next';
import Link from 'next/link';
import { useTranslations } from 'next-intl';
import { FavoriteButton } from '@/components/buttons/FavoriteButton';
import classes from '../RecipeDetail.module.css';
import type { RecipeHeroProps } from '../types';
import { getDifficultyColor } from '../utils';
 
export const RecipeHero = ({ recipe, isOwner }: Readonly<RecipeHeroProps>) => {
  const translate = useTranslations('recipeDetail');
  const translateMisc = useTranslations('misc');
 
  return (
    <Box className={classes.hero}>
      {recipe.imgSrc ? (
        <Image
          src={recipe.imgSrc}
          alt={recipe.title}
          className={classes.heroImage}
        />
      ) : (
        <Box className={classes.heroPlaceholder}>
          <IconChefHat size={80} color="var(--mantine-color-pink-4)" />
        </Box>
      )}
      <Box className={classes.heroOverlay} />
 
      {/* Top-right actions */}
      <Group className={classes.heroActions} gap="xs">
        <FavoriteButton
          recipeId={recipe.id}
          isFavorite={recipe.isFavorite ?? false}
          size="lg"
        />
        {isOwner && (
          <ActionIcon
            component={Link}
            href={`/recipes/${recipe.id}/edit` as Route}
            variant="subtle"
            color="white"
            size="lg"
          >
            <IconEdit size={22} />
          </ActionIcon>
        )}
      </Group>
 
      {/* Hero content */}
      <Box className={classes.heroContent}>
        <Title order={1} className={classes.heroTitle}>
          {recipe.title}
        </Title>
 
        {recipe.description && (
          <Text className={classes.heroDescription} mt={6}>
            {recipe.description}
          </Text>
        )}
 
        {/* Label pills */}
        <Group gap="xs" mt="sm">
          <Badge variant="light" className={classes.labelPill}>
            {translateMisc(`category-${recipe.category.key}`)}
          </Badge>
          <Badge
            variant="light"
            color={getDifficultyColor(recipe.difficultyLevel.key)}
            className={classes.labelPill}
          >
            {translateMisc(`level-${recipe.difficultyLevel.key}`)}
          </Badge>
          {recipe.labels.map((label) => (
            <Badge
              key={label.key}
              variant="filled"
              color="pink"
              className={classes.labelPill}
            >
              {translateMisc(`label-${label.key}`)}
            </Badge>
          ))}
        </Group>
 
        {/* Quick info pills */}
        <Box className={classes.quickInfo}>
          <span className={classes.infoPill}>
            <IconClock size={16} />
            {translate('cookingTime', { time: recipe.cookingTime })}
          </span>
          <span className={classes.infoPill}>
            <IconUsers size={16} />
            {translate('servingsCount', { count: recipe.servings })}
          </span>
          {recipe.ratingsCount > 0 && (
            <span className={classes.infoPill}>
              <IconFlame size={16} />
              {recipe.averageRating.toFixed(1)} ({recipe.ratingsCount})
            </span>
          )}
        </Box>
      </Box>
    </Box>
  );
};